library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity multiplier is
	generic (
		size		: in  positive
	);
	port (
		clk			: in  std_logic;
		reset		: in  std_logic;
		start		: in  std_logic;
		op1			: in  std_logic_vector(size-1 downto 0);
		op2			: in  std_logic_vector(size-1 downto 0);
		signed	: in  std_logic;
		result	: out std_logic_vector(size-1 downto 0);
		overflow: out std_logic;
		ready		: out std_logic
	);
end entity;

architecture behaviour of multiplier is
	signal mult_result : std_logic_vector(2*size-1 downto 0);
	signal operand1, operand2 : std_logic_vector(size-1 downto 0);
	signal zeroes, ones : std_logic_vector(size downto 0);

	-- overflow subsignals
	signal of_32bit_signed, of_32bit_unsigned : std_logic;
	signal of_signed : std_logic;
begin
	operand1 <= op1;
	operand2 <= op2;

	result <= mult_result(size-1 downto 0);

	-- check if high 32 bit range is used
	zeroes <= (others => '0');
	ones <= (others => '1');

	-- when unsigned multiplication: all upper word bits must be 0
	of_32bit_unsigned <= 
		'0' when (mult_result(2*size-1 downto size) = zeroes(size-1 downto 0)) else '1';
	-- when signed multiplication: the upper word bits must be equal to the
	--		sign bit (result msb)
	of_32bit_signed <= 
		'0' when (mult_result(2*size-1 downto size-1) = zeroes) else 
		'0' when (mult_result(2*size-1 downto size-1) = ones) else 
		'1';

--	-- check if sign changed
--	of_signed <= '1' when
--		-- pos * pos should be pos
--		(operand1(size-1) = '0' and operand2(size-1) = '0' and mult_result(size-1) = '1') or
--		-- pos * neg should be neg
--		(operand1(size-1) = '1' and operand2(size-1) = '0' and mult_result(size-1) = '0') or
--		-- neg * pos should be neg
--		(operand1(size-1) = '0' and operand2(size-1) = '1' and mult_result(size-1) = '0') or
--		-- neg * neg should be neg
--		(operand1(size-1) = '1' and operand2(size-1) = '1' and mult_result(size-1) = '1') else
--		'0';
	of_signed <= '0';

	-- combined overflow signal
	overflow <= of_32bit_unsigned when signed = '0' else
		of_32bit_signed or of_signed;

	-- multiplier pipeline
	process(clk, reset, start, mult_result) begin
		if (clk'event and clk = '1') then
			if (reset = '1') then
				ready <= '0';
				mult_result <= (others => '0');
			else
				mult_result <= operand1*operand2;
				ready <= start;
			end if;
		end if;
	end process;

end architecture;